package com.jinmdz.fmis.api.service;

import com.jinmdz.fmis.common.ext.StringBuilderExt;
import com.jinmdz.fmis.common.util.DateUtil;
import com.jinmdz.fmis.common.util.third.ZipUtil;
import com.jinmdz.fmis.core.util.LogUtil;
import com.jinmdz.fmis.dao.dao.GlobalDao;
import org.quartz.JobExecutionContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Date;

/**
 * MySql数据库定时任务Service类
 *
 * @author LiCongLu
 * @date 2019-12-23 09:17
 */
@Service("mySqlJobService")
public class MySqlJobService {

    /**
     * 数据库连接地址
     */
    @Value("${spring.datasource.url}")
    private String url;

    /**
     * 数据库账号名称
     */
    @Value("${spring.datasource.username}")
    private String username;

    /**
     * 数据库账号密码
     */
    @Value("${spring.datasource.password}")
    private String password;

    /**
     * 数据库定时备份路径
     */
    @Value("${mysql.back.dir-path}")
    private String dirPath;

    @Resource
    private GlobalDao globalDao;

    /**
     * 执行任务
     *
     * @param context 执行Context
     * @return
     * @author LiCongLu
     * @date 2019-12-23 10:10
     */
    public void executeInternal(JobExecutionContext context) {
        // 获取当前时间
        Date nowDate = globalDao.getNowForDate();
        String fileName = DateUtil.formatPattern(nowDate, "yyyy_MM_dd_HH_mm_ss");
        try {
            executeBackup(fileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 执行备份
     *
     * @param fileName 文件名称
     * @return
     * @author LiCongLu
     * @date 2020-05-21 11:43
     */
    public boolean executeBackup(String fileName) throws Exception {
        String sqlFileName = fileName + ".sql";
        String sqlFilePath = getBackSqlZipFilePath(sqlFileName);
        String execText = getBackExecText(sqlFilePath);
        if (exportDatabaseTool(execText)) {
            String zipFileName = sqlFileName.replace(".sql", ".zip");
            String zipFilePath = getBackSqlZipFilePath(zipFileName);
            ArrayList<File> fileList = new ArrayList<>();
            File sqlFile = new File(sqlFilePath);
            fileList.add(sqlFile);
            FileOutputStream out = new FileOutputStream(new File(zipFilePath));
            ZipUtil.toZip(fileList, out);
            sqlFile.delete();
            LogUtil.info("执行成功，命令脚本：" + execText);
            return true;
        } else {
            LogUtil.info("执行失败！" + execText);
        }
        return false;
    }

    /**
     * 执行备份导出脚本
     *
     * @param execText 执行命令行
     * @return
     * @author LiCongLu
     * @date 2019-12-23 10:36
     */
    public boolean exportDatabaseTool(String execText) throws Exception {
        try {
            Process process = Runtime.getRuntime().exec(getCommand(execText));
            //0 表示线程正常终止。
            if (process.waitFor() == 0) {
                return true;
            }
        } catch (Exception e) {
            throw e;
        }
        return false;
    }

    /**
     * 生成脚本执行命令行
     *
     * @param sqlFilePath 文件
     * @return
     * @author LiCongLu
     * @date 2019-12-23 10:05
     */
    private String getBackExecText(String sqlFilePath) throws Exception {
        try {
            String tempUrl = url.replace("jdbc:mysql://", "");
            String regex = "--=--";
            tempUrl = tempUrl.replace("?", regex).split(regex)[0];
            String[] temps = tempUrl.replace(":", regex).replace("/", regex).split(regex);
            String ip = temps[0];
            String port = temps[1];
            String databaseName = temps[2];
            String space = " ";
            String path = "";

            StringBuilderExt builder = new StringBuilderExt();
            String dumpFath = getCmdPath();
            if (dumpFath != null && dumpFath.length() > 0) {
                builder.format("{0}{1}{0}--opt{0}{0}--add-drop-database{0}{0}--add-drop-table{0}", space, dumpFath);
            } else {
                builder.format("{0}mysqldump{0}--opt{0}{0}--add-drop-database{0}{0}--add-drop-table{0}", space);
            }
            builder.format("{0}-h{1}{0}-P{2}{0}-u {3}{0}-p{4}", space, ip, port, username, password);
            builder.format("{0}--result-file={1}{0}--default-character-set=utf8{0}{2}", space, sqlFilePath, databaseName);

            return builder.toString();
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 获取 mysqldump 文件所在目录
     * 如果不存在，则返回空字符串
     *
     * @param
     * @return
     * @author LiCongLu
     * @date 2019-12-23 10:05
     */
    private String getCmdPath() throws Exception {
        try {
            String os = System.getProperty("os.name");
            File file = ResourceUtils.getFile("classpath:");
            if (os.toLowerCase().startsWith("win")) {
                file = new File(file.getAbsolutePath(), "mysqldump.exe");
            } else {
                file = new File(file.getAbsolutePath(), "mysqldump");
            }
            if (file != null && file.exists()) {
                return file.getAbsolutePath();
            }
        } catch (Exception e) {
            throw e;
        }
        return "";
    }

    /**
     * 生成备份文件路径
     *
     * @param fileName 文件名称
     * @return
     * @author LiCongLu
     * @date 2019-12-23 10:05
     */
    private String getBackSqlZipFilePath(String fileName) {
        String backPath = dirPath;
        File backFile = new File(backPath);
        if (!backFile.exists()) {
            backFile.mkdirs();
        }

        return new File(backPath, fileName).getAbsolutePath();
    }

    /**
     * 执行命令
     *
     * @param command 命令文本
     * @return
     * @author LiCongLu
     * @date 2019-12-23 10:05
     */
    private String[] getCommand(String command) throws Exception {
        try {
            String os = System.getProperty("os.name");
            String shell = "/bin/bash";
            String c = "-c";
            if (os.toLowerCase().startsWith("win")) {
                shell = "cmd";
                c = "/c";
            }
            String[] cmd = {shell, c, command};
            return cmd;
        } catch (Exception e) {
            throw e;
        }
    }
}
